package com.algoshow.controller;



import com.algoshow.view.FirstMenu;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map;

import static com.algoshow.utils.SystemConstants.*;

public class BasePage extends JFrame {
    // 当前要展示的算法名
    public String algoName;
    // 启动新线程所控制的面板
    public JPanel panel;
    // 主面板，就是主线程控制的面板
    public JPanel mainPanel;
    // 启动的那个新的线程
    public Thread timer;
    // 这个是开始暂停按钮的控制项
    public boolean isWorking = false;
    // 通用颜色
    public static final Color GREEN = new Color(13,128,0);

    public static final Color blur = new Color(168,212,223);

    public static final Color red = new Color(218,42,56);

    public static final Color yellow = new Color(253,168,0);

    public static final Color gray = new Color(238,238,238);

    // 展示算法的 X Y 位置
    public static final Integer startX = 120;
    public static final Integer startY = 600;
    // 伪代码的X Y位置
    public static final Integer lineX = 1280;
    public static final Integer lineY = 200;

    // 监控变量的X Y位值
    public static final Integer paramX = 1300;
    public static final Integer paramY = 800;

    // 每行的字体大小
    public Integer fontSize = 24;
    // 执行到第几行
    public Integer codeLine = 0;

    public Map<String, String> map = new HashMap<>();

    // 目前是几倍速
    public boolean is1XSpeed = true;

    // 暂停时间 单位ms
    public Integer SUSPEND = 1000;

    public static final String bracketCode ="    function isValid(s) \n" +
            "       if (S.size() % 2 == 1) return;\n" +
            "        st = new Stack();\n" +
            "        for (i = 0; i < s.length(); i++) \n" +
            "            if (s.charAt(i) == '(' \n" +
            "                or s.charAt(i) == '[' \n"+
            "                or s.charAt(i) == '{') \n" +
            "                st.push(s.charAt(i));\n" +
            "            else \n" +
            "                if (!st.isEmpty() and \n"+
            "                check(st.peek(), s.charAt(i))) \n" +
            "                    st.pop();\n" +
            "                else \n" +
            "                    return false;\n" +
            "        return st.isEmpty();";

    public static final String preorderCode = "void preorder(TreeNode root) {\n" +
            "        if (root == null) {\n" +
            "            return;\n" +
            "        }\n" +
            "        print(root.val)\n" +
            "        preorder(root.left);\n" +
            "        preorder(root.right);\n" +
            "    } ";

    public static final String inorderCode = "void inorder(TreeNode root) {\n" +
            "        if (root == null) {\n" +
            "            return;\n" +
            "        }\n" +
            "        preorder(root.left);\n" +
            "        print(root.val)\n" +
            "        preorder(root.right);\n" +
            "    }";

    public static final String postorderCode = "void postorder(TreeNode root) {\n" +
            "        if (root == null) {\n" +
            "            return;\n" +
            "        }\n" +
            "        preorder(root.left);\n" +
            "        preorder(root.right);\n" +
            "        print(root.val)\n" +
            "    }";
    public static final String levelorderCode = " void levelorder(TreeNode root) {\n" +
            "        Queue<TreeNode> q = new \n" +
            "           LinkedList<>();\n" +
            "        q.add(root);\n" +
            "        while (!q.isEmpty()) {\n" +
            "            int size = q.size();\n" +
            "            for (int i = 0; i < size; i++) {\n" +
            "                TreeNode node = q.poll();\n" +
            "                if (node.left != null) \n" +
            "                    q.add(node.left);\n" +
            "                if (node.right != null) \n" +
            "                    q.add(node.right);\n" +
            "            }\n" +
            "        }\n" +
            "    }";
    public static final String bubbleCode = "   for (int i = 0; i < n - 1; i++) {\n" +
            "       for (int j = 0; j < n - i - 1; j++) {\n" +
            "           if (arr[j] > arr[j + 1]) {\n" +
            "               swap(arr[j], arr[j + 1]);\n" +
            "           }\n" +
            "       }\n" +
            "    }";
    public static final String fastCode = "function quickSort(arr, low, high) \n" +
            "    if (low > high) return;\n" +
            "    i = low, j = high, temp = arr[low];\n" +
            "    while (i < j) {\n" +
            "        while (temp <= arr[j] and i < j) \n" +
            "           j--;\n" +
            "        while (temp >= arr[i] and i < j) \n" +
            "           i++;\n" +
            "        if (i < j) \n" +
            "           swap(arr[i], arr[j]);\n" +
            "    }\n" +
            "    arr[low] = arr[i], arr[i] = temp;\n" +
            "    quickSort(arr, low, j - 1);\n" +
            "    quickSort(arr, j + 1, high);";
    public static final String selectCode = "for (int i = 0; i < n - 1; i++) {\n" +
            "    int minIndex = i;\n" +
            "    for (int j = i + 1; j < n; j++) {\n" +
            "        if (arr[j] < arr[minIndex]) {\n" +
            "            minIndex = j;\n" +
            "        }\n" +
            "    }\n" +
            "    swap(arr[minIndex], arr[i]);\n" +
            "}";
    public static final String insertCode = "for (int i = 1; i < n; i++) {\n" +
            "    int key = arr[i];\n" +
            "    int j = i - 1;\n" +
            "    for (; j >= 0 && arr[j] > key; j--) {\n" +
            "        arr[j + 1] = arr[j];\n" +
            "    }\n" +
            "    arr[j + 1] = key;\n" +
            "}";
    public static final String arrayInsertCode = "    void insert(int index, int value) {\n" +
            "        for (int j=a.size()-1,i=a.size()-2;\n" +
            "                        i >= 0; i--, j--) {\n" +
            "            a[i] = a[j];\n" +
            "            if (i == index) {\n" +
            "                a[i] = value;\n" +
            "                break;\n" +
            "            }\n" +
            "        }\n" +
            "    }";
    public static final String arrayDeleteCode = "    void delete(int index) {\n" +
            "        int pre = arr[arr.size() - 1];\n" +
            "        for (i = arr.size() - 2; i >= 0; i--)\n" +
            "            int temp = a[i];\n" +
            "            a[i] = pre;\n" +
            "            pre = temp;\n" +
            "            if (i == index) break;\n" +
            "        }\n" +
            "    }";
    public static final String listInsertCode = " void insert(int index, int value) {\n" +
            "        ListNode cur = head;\n" +
            "        while (index > 0) {\n" +
            "            cur = cur.next;\n" +
            "            index--;\n" +
            "        }\n" +
            "        ListNode node = new ListNode(value);\n" +
            "        node.next = cur.next;\n" +
            "        cur.next = node;\n" +
            "    }";
    public static final String listDeleteCode = " void delete(int index) {\n" +
            "        ListNode cur = head;\n" +
            "        while (index > 0) {\n" +
            "            cur = cur.next;\n" +
            "            index--;\n" +
            "        }\n" +
            "        cur.next = cur.next.next;\n" +
            "    }";
    public static final String stackPreorderCode = " void stackPreorder(TreeNode root) \n" +
            "        stack.push(root);\n" +
            "        while (!stack.isEmpty()) \n" +
            "            TreeNode node = stack.pop();\n" +
            "            if (node != null) {\n" +
            "                if (node.right != null) \n" +
            "                    stack.push(node.right);\n" +
            "                if (node.left != null) \n" +
            "                    stack.push(node.left);\n" +
            "                stack.push(node);\n" +
            "                stack.push(null);\n" +
            "            } else {\n" +
            "               print(stack.pop());\n" +
            "            }";
    public static final String stackInorderCode = " void stackInorder(TreeNode root) \n" +
            "       stack.push(root);\n" +
            "        while (!stack.isEmpty()) \n" +
            "            TreeNode node = stack.pop();\n" +
            "            if (node != null) {\n" +
            "                if (node.right != null ) \n" +
            "                    stack.push(node.right);\n" +
            "                stack.push(node);\n" +
            "                stack.push(null);\n" +
            "                if (node.left != null) \n" +
            "                    stack.push(node.left);\n" +
            "            } else {\n" +
            "                print(stack.pop());\n" +
            "            }";
    public static final String stackPostorderCode = " void stackPostOrder(TreeNode root) \n" +
            "        stack.push(root);\n" +
            "        while (!stack.isEmpty()) \n" +
            "            TreeNode node = stack.pop();\n" +
            "            if (node != null) {\n" +
            "                stack.push(node);\n" +
            "                stack.push(null);\n" +
            "                if (node.right != null) \n" +
            "                    stack.push(node.right);\n" +
            "                if (node.left != null) \n" +
            "                    stack.push(node.left);\n" +
            "            } else {\n" +
            "                print(stack.pop());\n" +
            "            }";


    public JButton firstMenuButton;
    public BasePage() throws HeadlessException {
        this.setSize(SYSTEM_WIDTH, SYSTEM_HEIGHT);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setLocationRelativeTo(null); // 设置窗口位置为屏幕中心

        // test start
        JPanel panel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g;
                // 加载背景图
                Image backgroundImage = new ImageIcon("src/resources/showAlgoBackground.jpg").getImage();
                g.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this);
                drawHighLine(g);
                drawCode(g, map.get(algoName));
                drawParam(g);
                drawAlgo(g);
            }
        };
        panel.setLayout(null);  // 使用绝对布局以便手动设置按钮位置
        this.panel = panel;

        // test end
        JButton startButton = new JButton("开始");
        startButton.setBounds(5,10,350,100);
        startButton.setContentAreaFilled(false);      //按钮透明
        startButton.setBorderPainted(false);  //无边框
        startButton.setFont(new Font("宋体", Font.ROMAN_BASELINE, 60));
        startButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        startButton.setForeground(Color.BLACK);
        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!isWorking) {
                    if (timer == null) {
                        startThread();
                    } else {
                        timer.resume();
                    }
                    isWorking = true;
                }
            }
        });
        // 设置鼠标动作事件监听器
        startButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                startButton.setForeground(Color.WHITE);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                startButton.setForeground(Color.BLACK);
            }
        });

        JButton pauseButton = new JButton("暂停");
        pauseButton.setBounds(380,10,350,100);
        pauseButton.setContentAreaFilled(false);      //按钮透明
        pauseButton.setBorderPainted(false);  //无边框
        pauseButton.setFont(new Font("宋体", Font.ROMAN_BASELINE, 60));
        pauseButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        pauseButton.setForeground(Color.BLACK);
        pauseButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (isWorking) {
                    pauseSorting();
                    isWorking = false;
                }
            }
        });
        // 设置鼠标动作事件监听器
        pauseButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                pauseButton.setForeground(Color.WHITE);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                pauseButton.setForeground(Color.BLACK);
            }
        });

        firstMenuButton = new JButton("返回");
        firstMenuButton.setBounds(1120,10,350,100);
        firstMenuButton.setContentAreaFilled(false);      //按钮透明
        firstMenuButton.setBorderPainted(false);  //无边框
        firstMenuButton.setFont(new Font("宋体", Font.ROMAN_BASELINE, 60));
        firstMenuButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        firstMenuButton.setForeground(Color.BLACK);
        new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

            }
        };
        // 设置鼠标动作事件监听器
        firstMenuButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                firstMenuButton.setForeground(Color.WHITE);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                firstMenuButton.setForeground(Color.BLACK);
            }
        });

        JButton routeButton = new JButton("2X");
        routeButton.setBounds(748,10,350,100);
        routeButton.setContentAreaFilled(false);      //按钮透明
        routeButton.setBorderPainted(false);  //无边框
        routeButton.setFont(new Font("宋体", Font.ROMAN_BASELINE, 60));
        routeButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        routeButton.setForeground(Color.BLACK);
        // 调速算法
        routeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (is1XSpeed) {
                    // 调成两倍速
                    SUSPEND -= 500;
                    routeButton.setText("1X");
                    is1XSpeed = false;
                } else {
                    // 调成一倍速
                    SUSPEND += 500;
                    routeButton.setText("2X");
                    is1XSpeed = true;
                }
            }
        });

        // 设置鼠标动作事件监听器
        routeButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                routeButton.setForeground(Color.WHITE);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                routeButton.setForeground(Color.BLACK);
            }
        });

        //initOtherButton();

        // 返回主菜单按钮， 1. 先将这个算法的线程给杀死
        JPanel buttonPanel = new JPanel();
        panel.add(startButton);
        panel.add(pauseButton);
        panel.add(firstMenuButton);
        panel.add(routeButton);

        mainPanel = new JPanel(new BorderLayout());
        panel.add(buttonPanel);
        mainPanel.add(panel, BorderLayout.CENTER);
        add(mainPanel);
        initCode();
    }

    // 每个算法类返回的按钮
    public void initOtherButton(){}
    // 留给子类区实现算法的展示
    public void drawAlgo(Graphics g) {}
    // 留给子类去实现变量监控展示
    public void drawParam(Graphics g) {}

    private void initCode() {
        map.put("preorder", preorderCode);
        map.put("inorder", inorderCode);
        map.put("postorder", postorderCode);
        map.put("bubble", bubbleCode);
        map.put("fast", fastCode);
        map.put("insert", insertCode);
        map.put("select", selectCode);
        map.put("listInsert", listInsertCode);
        map.put("listDelete", listDeleteCode);
        map.put("arrayInsert", arrayInsertCode);
        map.put("arrayDelete", arrayDeleteCode);
        map.put("levelorder", levelorderCode);
        map.put("bracket", bracketCode);
        map.put("stackPreorder", stackPreorderCode);
        map.put("stackInorder", stackInorderCode);
        map.put("stackPostorder", stackPostorderCode);
    }

    public void renderLine(int line) {
        codeLine = line;
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        panel.repaint();
    }

    // 渲染
    public void render(Integer line, Integer time) {
        if (line != null) {
            renderLine(line);
        }
        panel.repaint();
        try {
            Thread.sleep(SUSPEND - time);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    // 高亮行且渲染
    public void render(Integer line) {
        renderLine(line);
        panel.repaint();
        try {
            Thread.sleep(SUSPEND - 300);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    // 单渲染不高亮行
    public void render() {
        panel.repaint();
        try {
            Thread.sleep(SUSPEND);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public void pauseSorting() {
        if (timer != null && !timer.isInterrupted()) {
           timer.suspend();
        }
    }

    public void drawCode(Graphics g, String code) {
        Font font = new Font("Arial", Font.BOLD, 30);
        g.setFont(font);
        if (code == null) {
            return;
        }
        g.setColor(Color.BLACK);
        FontMetrics fm = g.getFontMetrics();
        fontSize = fm.getHeight();
        String[] lines = code.split("\n");
        int y = lineY; // 初始绘制的垂直位置

        for (String line : lines) {
            g.drawString(line, lineX, y);
            y += fontSize; // 增加垂直位置，以便绘制下一行
        }
    }

    public void drawHighLine(Graphics g) {
        g.setColor(yellow);
        g.fillRect(lineX, lineY + fontSize * codeLine, 500, -fontSize);
    }
    //给子类去重写
    public void startThread() {
    }

    public static void main(String[] args) {
        new BasePage();
    }

}
